package com.lagou.edu.bean;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.utils.ClassUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AnnoBeanFactory {

    private String packagePath;


    /**
     * 相当于容器
     */
    public static ConcurrentHashMap<String, Object> beans=new ConcurrentHashMap<>();

    public AnnoBeanFactory(String packagePath) {
        this.packagePath=packagePath;
    }

    /**
     * 根据BeanId获取对象
     */
    public Object getBean(String beanId) throws Exception {
        //通过扫描包路径获取到所有带自定义注解的类
        List<Class> classes=getAnnoClass();
        if (classes == null || classes.isEmpty()) {
            throw new Exception("no anno beans");
        }
         //处理@autowired
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object object=entry.getValue();
            createAutowireBean(object);
        }
          // 处理@Transactional
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object object=entry.getValue();
            Class cls=object.getClass();
            Transactional transactionalAnnotation=(Transactional) cls.getAnnotation(Transactional.class);
            if (transactionalAnnotation != null) {
                ProxyFactory proxyFactory=(ProxyFactory) beans.get("proxyFactory");
                //将容器内的对象修改为 cglib代理对象
                Object cglibProxyObject=proxyFactory.getCglibProxy(object);
                beans.put(entry.getKey(), cglibProxyObject);
            }
        }
        Object object=beans.get(beanId);
        return object;
    }

    /**
     * 通过反射生产bean 注入容器 @Autowired
     */
    public void createAutowireBean(Object object) throws IllegalArgumentException, IllegalAccessException {
        // 1.获取类的属性是否存在 获取bean注解
        Class<? extends Object> classInfo=object.getClass();
        Field[] declaredFields=classInfo.getDeclaredFields();
        for (Field field : declaredFields) {
            Autowired autowiredAnnotation=field.getDeclaredAnnotation(Autowired.class);
            if (autowiredAnnotation != null) {
                // 属性名称
                String name=field.getName();
                Object bean=beans.get(name);
                if (bean != null) {
                    // 私有访问允许访问
                    field.setAccessible(true);
                    // 给属性赋值
                    field.set(object, bean);
                    continue;
                }
            }
        }

    }

    /**
     * @param classes 判断是否有@Service
     *
     *
     * */
    public ConcurrentHashMap<String, Object> createServiceBean(List<Class> classes)
            throws InstantiationException, IllegalAccessException {
        for (Class cls : classes) {
            // 初始化对象
            Object newInstance=cls.newInstance();
            Service service=(Service) cls.getDeclaredAnnotation(Service.class);
            String value=service.value();
            // 获取类的简写名称
            String beanId=toLowerCaseFirstOne(cls.getSimpleName());
            if (!StringUtils.isEmpty(value)) {
                beanId=value;
            }

            beans.put(beanId, newInstance);
        }
        return beans;
    }


    /**
     * 有参构造写入扫描地址
     * 根据路径获取所有的class
     * 判断是否有@Annotation
     * 返回含有注解的class集合
     */
    public List<Class> getAnnoClass() throws Exception {
        if (StringUtils.isEmpty(packagePath)) {
            throw new Exception("packagePath cannot be null");
        }
        List<Class<?>> classes=ClassUtil.getClasses(packagePath);
        List<Class> annoCls=new ArrayList<Class>();
        for (Class cls : classes) {
            Service service=(Service) cls.getDeclaredAnnotation(Service.class);
            if (service != null) {
                annoCls.add(cls);
                continue;
            }
        }
        createServiceBean(annoCls);
        return annoCls;
    }


    /**
     * 首字母转小写
     *
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

}
